package com.tsyz.servlet.config;

import com.tsyz.servlet.filter.TsyzJwtAuthenticationFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.http.HttpServletResponse;

/**
 * @author ext.zhaoke14
 */
@Slf4j
@Configuration
@EnableWebSecurity
public class TsyzSecurityConfig {


    /**
     * 用于处理JWT认证的过滤器，负责验证请求中的JWT令牌
     */
    @Autowired
    private TsyzJwtAuthenticationFilter jwtAuthenticationFilter;

    /**
     * 控制是否启用Swagger相关路径的访问权限
     */
    @Value("${swagger.enabled:false}")
    private boolean swaggerEnabled;

    /**
     * 获取身份验证管理器。
     *
     * @param config 身份验证配置对象。
     * @return 身份验证管理器。
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        log.info("获取身份验证管理器-authenticationManager");
        return config.getAuthenticationManager();
    }

    /**
     * 配置Spring Security的安全过滤器链
     *
     * @param http Spring Security的HTTP安全配置对象
     * @return 配置好的安全过滤器链
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        log.info("配置Spring Security的安全过滤器链-filterChain");
        // 禁用CSRF保护，因为使用JWT不需要会话
        http.csrf().disable().cors().and()
                // 禁用session，因为使用JWT进行认证
                .sessionManagement()
                // 配置会话管理策略
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                // 配置请求授权规则
                .authorizeHttpRequests(authz -> {
                    // 允许所有人访问登录相关路径
                    authz.antMatchers("/api/auth/login", "/api/auth/logout").permitAll();

                    // 允许所有人访问静态资源（CSS, JS, 图片等）
                    authz.antMatchers("/static/css/**", "/static/js/**", "/static/images/**", "/assets/images/**", "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/**/*.gif", "/favicon.ico", "/**/*.html").permitAll();

                    // 根据配置决定是否放行Swagger路径
                    if (swaggerEnabled) {
                        authz.antMatchers("/swagger-ui/**", "/swagger-resources/**", "/v3/api-docs/**", "/webjars/**").permitAll();
                    }

                    // 允许认证用户访问所有API接口
                    authz.antMatchers("/api/**").authenticated();

                    // 其他所有请求都需要认证
                    authz.anyRequest().authenticated();
                });
        // 配置访问拒绝处理器
        http.exceptionHandling(ex -> ex.accessDeniedHandler(accessDeniedHandler()).authenticationEntryPoint(authenticationEntryPoint()))
                // 禁用表单登录，因为我们使用JWT认证
                .formLogin().disable()
                // 禁用HTTP基本认证
                .httpBasic().disable();

        // 添加JWT认证过滤器
        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }


    /**
     * 自定义访问拒绝处理器
     * 当用户访问没有权限的资源时，对于API请求返回403状态码，对于页面请求跳转到登录页
     */
    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            // 判断是否为API请求
            String requestURI = request.getRequestURI();
            if (requestURI.startsWith("/api/")) {
                // 对于API请求，返回403状态码和JSON响应
                response.setStatus(HttpServletResponse.SC_FORBIDDEN);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("{\"success\":false,\"message\":\"访问被拒绝\",\"code\":403}");
            } else {
                // 对于页面请求，跳转到登录页
                response.sendRedirect("/api/auth/login");
            }
        };
    }

    /**
     * 自定义认证入口点
     * 当未认证用户访问需要认证的资源时，对于API请求返回401状态码，对于页面请求跳转到登录页
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            // 判断是否为API请求
            String requestUri = request.getRequestURI();
            if (requestUri.startsWith("/api/")) {
                // 对于API请求，返回401状态码和JSON响应
                response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
                response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write("{\"success\":false,\"message\":\"未认证\",\"code\":401}");
            } else {
                // 对于页面请求，跳转到登录页
                response.sendRedirect("/api/auth/login");
            }
        };
    }
}
